package model.solver;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import model.NoSuchDirectoryException;
import controller.solver.ImportSolver;
import controller.solver.MiniSat;
import controller.solver.RSat;
import controller.solver.Solver;

/**
 * Manage the creation of preprocessor.
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class SolverFactory {

	private File				directory;
	private Set<ESolver>		available		= new HashSet<ESolver>();
	private Set<ImportESolver>	availableImport	= new HashSet<ImportESolver>();

	/**
	 * Create a solver factory.
	 * 
	 * @param directory
	 *            the directory where are the executable file.
	 */
	public SolverFactory(File directory) {
		this.directory = directory;
		for (ESolver p : ESolver.values())
			available.add(p);
	}

	/**
	 * Return the available solver.
	 * 
	 * @return the available solver.
	 */
	public Set<ESolver> getAvailableSolver() {
		return available;
	}

	/**
	 * Add an available imported solver.
	 * 
	 * @param solver
	 *            the solver to add
	 */
	public void addAvailableImport(ImportESolver solver) {
		availableImport.add(solver);
	}

	/**
	 * Remove an available imported solver.
	 * 
	 * @param solver
	 *            the solver to remove
	 */
	public void removeAvailableImport(ImportESolver solver) {
		availableImport.remove(solver);
	}

	/**
	 * Return the available imported solver.
	 * 
	 * @return the available solver.
	 */
	public Set<ImportESolver> getAvailableImport() {
		return availableImport;
	}

	/**
	 * Return the available imported solver equivalent to {@link ImportESolver} passing by
	 * arguments. This method is useful when you import a session from XML format session that
	 * contains imported solver : you can't just create a {@link ImportESolver} using the
	 * information of the XML file because you need to have the exact {@link ImportESolver} object
	 * store in the factory because some method may use code like "imported1 == imported2 " to
	 * recognize an {@link ImportESolver} instead of the equals method.
	 * 
	 * @param toget
	 *            the XML value of the solver to get.
	 * @return the corresponding {@link ImportESolver}.
	 * 
	 */
	public ImportESolver getAvailableImportByXML(String toget) {
		for (ImportESolver solver : availableImport)
			if (solver.getXmlValue().equals(toget))
				return solver;
		return null;
	}

	/**
	 * Create a solver of the specified type.
	 * 
	 * @param solver
	 *            solver needed.
	 * @return the solver, null if it can't be created.
	 * @throws NoSuchDirectoryException
	 *             if the directory where the executable file should be doesn't exist
	 */
	public Solver createSolver(ESolver solver) throws NoSuchDirectoryException {
		if (solver == null)
			return null;

		try
		{
			switch (solver) {
			case MINISAT:
				return new MiniSat(directory);
			case RSAT:
				return new RSat(directory);
			default:
				return null;
			}
		} catch (IOException e)
		{
			throw new NoSuchDirectoryException();
		}
	}

	/**
	 * Create a {@link ImportSolver}
	 * 
	 * @param solver
	 *            solver to create
	 * 
	 * @return the solver.
	 * @throws NoSuchDirectoryException
	 *             if the directory where the executable file should be doesn't exist
	 */
	public ImportSolver createImportSolver(ImportESolver solver) throws NoSuchDirectoryException {
		if (solver == null)
			return null;

		try
		{
			return new ImportSolver(solver, directory);
		} catch (IOException e)
		{
			throw new NoSuchDirectoryException();
		}
	}


	/**
	 * Create a {@link MiniSat} solver.
	 * 
	 * @return the solver.
	 * @throws NoSuchDirectoryException
	 *             if the directory where the executable file should be doesn't exist
	 */
	public MiniSat createMiniSatSolver() throws NoSuchDirectoryException {
		try
		{
			return new MiniSat(directory);
		} catch (IOException e)
		{
			throw new NoSuchDirectoryException();
		}
	}

	/**
	 * Create a {@link RSat} solver.
	 * 
	 * @return the solver
	 * @throws NoSuchDirectoryException
	 *             if the directory where the executable file should be doesn't exist
	 */
	public RSat createRSatSolver() throws NoSuchDirectoryException {
		try
		{
			return new RSat(directory);
		} catch (IOException e)
		{
			throw new NoSuchDirectoryException();
		}
	}

	/**
	 * Return the default directory where the executable file a re suppose to be.
	 * 
	 * @return the default directory where the executable file a re suppose to be.
	 */
	public File getDirectory() {
		return directory;
	}

	/**
	 * Set the default directory where the executable file a re suppose to be.
	 * 
	 * @param directory
	 *            the directory.
	 */
	public void setDirectory(File directory) {
		this.directory = directory;
	}

}
